<?php


namespace app\common\library;


use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\Manager;
use MongoDB\Driver\Query;


class himongo
{

    var $_mgr = null;
    var $_namespace_default = 'ebike.ebike';
    var $_namespace = null;

    function mrg()
    {
        if (empty($this->_mgr)) {
            $this->_mgr = new Manager(config('mongodb.dsn'));
        }

        return $this->_mgr;
    }

    function collection()
    {
        if (!empty($this->_namespace)) {
            return $this->_namespace;
        } else {
            return $this->_namespace_default;
        }
    }

    static function db($namespace = null)
    {
        static $_thiz = null;
        if (empty($_thiz)) {
            $_thiz = new himongo();
        }
        if (!empty($namespace)) {
            $_thiz->_namespace = 'ebike.' . $namespace;
        } else {
            $_thiz->_namespace = null;
        }
        return $_thiz;
    }

    function insert($data_array)
    {
        $bulk = new BulkWrite();
        $bulk->insert($data_array);

        $ret = $this->mrg()->executeBulkWrite($this->collection(), $bulk);
        return $ret;
    }

    function update($where, $data_array, $upsert = false)
    {
        // $v = new vtimer();
        $bulk = new BulkWrite();
        $data = [
            '$set' => $data_array,
            '$inc' => ['nupdate' => 1],
        ];

        $bulk->update($where, $data, array('upsert' => $upsert));
        $ret = $this->mrg()->executeBulkWrite($this->collection(), $bulk);


        // $cost = $v->cost();

        $retstring = [];
        $retstring[] = "Insert=" . $ret->getInsertedCount();
        $retstring[] = "Matched=" . $ret->getMatchedCount();
        $retstring[] = "Updated=" . $ret->getModifiedCount();
        $retstring[] = "Upserted=" . $ret->getUpsertedCount();
        $retstring[] = "Deleted=" . $ret->getDeletedCount();

        //hilog::debug("mongo update where:" . json_encode($where) . " params:" . json_encode($data_array), $ret, "cost = {$cost} ", implode(",", $retstring));

        return $ret->getModifiedCount();
    }

    function delete($where)
    {
        $bulk = new BulkWrite();

        $bulk->delete($where, ['limit' => 0]);
        $ret = $this->mrg()->executeBulkWrite($this->collection(), $bulk);

        /*
          hilog::debug("Inserted %d document(s)\n", $ret->getInsertedCount());
          hilog::debug("Matched  %d document(s)\n", $ret->getMatchedCount());
          hilog::debug("Updated  %d document(s)\n", $ret->getModifiedCount());
          hilog::debug("Upserted %d document(s)\n", $ret->getUpsertedCount());
          hilog::debug("Deleted  %d document(s)\n", $ret->getDeletedCount());
         */

        return $ret->getModifiedCount();
    }

    function find($where = null)
    {

        $options = [
            'limit' => 10,
        ];

        $query = new Query($where, $options);

        $rows = $this->mrg()->executeQuery($this->collection(), $query);

        $result = array();
        foreach ($rows as $row) {
            $result[] = $row;
        }

        return $result;
    }

    function near($lng, $lat, $max_distance, $limit, $condition, $projection = [])
    {

        $nearSphere = [
            '$geometry' =>
                [
                    'type' => 'Point',
                    'coordinates' => [doubleval($lng), doubleval($lat)]
                ],
        ];

        if ($max_distance > 0) {
            $nearSphere['$maxDistance'] = floor($max_distance);
        }
        $geo_parmas = ['point' =>
            ['$nearSphere' => $nearSphere]
        ];

        if (!is_array($condition)) {
            $condition = array();
        }

        $params = $geo_parmas + $condition;


        $options = [
            'limit' => $limit,
        ];

        if (!empty($projection)) {
            $options['projection'] = $projection;
        }

        $result = array();
        $ex = '';
        try {

            $query = new Query($params, $options);

            $rows = $this->mrg()->executeQuery($this->collection(), $query);

            foreach ($rows as $row) {
                $result[] = (array)$row;
            }

        } catch (Exception  $e) {
            $ex = $e->getMessage();
        }

        return $result;
    }

    function runconmand_intersects($coordinate, $condition, $limit)
    {
        //db.geom.find({"demo": {$geoIntersects: {$geometry:{ "type" : "Point", "coordinates" : [ 17.613919673106714, 78.73489379882812] }}}});
        $geoIntersects = [
            '$geometry' => [
                'type' => 'Point',
                'coordinates' => [
                    doubleval($coordinate[0]), doubleval($coordinate[1])
                ]
            ]
        ];

        $geo_parmas = ['polygon' =>
            [
                '$geoIntersects' => $geoIntersects
            ]
        ];

        if (!is_array($condition)) {
            $condition = array();
        }

        $params = $geo_parmas + $condition;

        $options = [
            'limit' => $limit,
        ];

        $ex = null;
        $result = array();
        try {
            $query = new Query($params, $options);

            $rows = $this->mrg()->executeQuery($this->collection(), $query);

            foreach ($rows as $row) {
                $result[] = (array)$row;
            }
        } catch (Exception  $e) {
            $ex = $e->getMessage();
        }
        return $result;
    }

}
